#include "ioreader.h"
#include "rtdb.h"
#include "xnserial.h"

//#define EMS_CTRL_SWITCH_CLOSE_STR    "IO控制汇流开关合闸."
//#define EMS_CTRL_SWITCH_OPEN_STR     "IO控制汇流开关分闸."
#define SERIAL_IO_DEV_CONN_ERROR	"串口继电器通信故障."
#define SERIAL_IO_DEV_CONN_OK		"串口继电器通信恢复."

#define SWITCH_CLOSED_STR    		"汇流开关合闸."
#define SWITCH_OPENED_STR     		"汇流开关分闸."

//unsigned char  g_DIState = 0;// 4路继电器输出4路开关量输入（转发卡） 的DI状态 DI1和DI2闭合时值为3， 只有DI3闭合时值为4
//unsigned char  g_DOState = 0;// 4路继电器输出4路开关量输入（转发卡） 的DO状态 DO1和DO2闭合时值为3， 只有DO3闭合时值为4
//int      g_bReadDiFlag = 0; // 是否已经获取到DI状态
//int      g_bReadDoFlag = 0; // 是否已经获取到DO状态
//quint16  g_connFailedCount = 0; // 通迅故障计时，通迅正常时清0

int IOReader::getParamFromBuffer(char* pData, quint16& uiParamVal)
{
	uiParamVal = (unsigned char)*pData;
	uiParamVal = uiParamVal * 256;

	++pData;

	uiParamVal += (unsigned char)*pData;

	return 0;
}

int IOReader::getParamFromBuffer(char* pData, quint32& uiParamVal)
{
	quint16 smallVal;
	quint16 big;
	big = (unsigned char)*pData;

	big = big * 256;
	++pData;
	big += (unsigned char)*pData;

	++pData;
	smallVal = (unsigned char)*pData;

	smallVal = smallVal * 256;
	++pData;
	smallVal += (unsigned char)*pData;
    uiParamVal = big*256*256+smallVal;
	return 0;
}

int IOReader::addParam2Buffer(char* pData, quint16 uiParamVal)
{
	*pData = (char)(uiParamVal >> 8);

	++pData;
	*pData = (char)(uiParamVal);

	return  0;
}

QString IOReader::getMsgFromIndexStep(int iIndexStep)
{
    QString tmpInfo = QString("Step%1").arg(iIndexStep);
	return tmpInfo;
}

void IOReader::printSendInfo(int iIndexStep, char* pSendBufData, int iLen)
{
	QString strPrintInfo = "";
	QChar aFillChar = '0';

	for (int i = 0; i < iLen; ++i)
	{
		strPrintInfo += QString("%1 ").arg((uchar)*(pSendBufData + i), 2, 16, aFillChar);
	}

	strPrintInfo = strPrintInfo.toUpper();

	strPrintInfo =  QString("Dev%1 Send ").arg(m_iDevIndex+1) + getMsgFromIndexStep(iIndexStep) + " Datagram:" + strPrintInfo;
	sendLog(RUN_LOG_MODBUS_DEV, strPrintInfo);
}

void IOReader::printReceInfo(int iIndexStep, char* pSendBufData, int iLen)
{
	QString strPrintInfo = "";
	QChar aFillChar = '0';

	for (int i = 0; i < iLen; ++i)
	{
		strPrintInfo += QString("%1 ").arg((uchar)*(pSendBufData + i), 2, 16, aFillChar);
	}

	strPrintInfo = strPrintInfo.toUpper();

	strPrintInfo = QString("Dev%1 Rece ").arg(m_iDevIndex+1)  + getMsgFromIndexStep(iIndexStep) + " Datagram:" + strPrintInfo;
	sendLog(RUN_LOG_MODBUS_DEV, strPrintInfo);
}

quint16 IOReader::getUint16(float fVal)
{
	//负float型数据转成UINT,UINT16时，需要先转换成short型或int型数据，否则结果为0
	int iVal = fVal;
	quint16 temp = iVal;
	return temp;
}

float IOReader::getRealVal(quint16 uVal, float rate)
{
	short iVal = uVal;
	float fVal  = iVal / rate;
	return fVal;
}

float IOReader::getRealVal(quint32 uVal, float rate)
{
	int iVal = uVal;
	float fVal  = iVal / rate;
	return fVal;
}

void IOReader::sendLog(int iLogType, const QString& strLog)
{
	writeKgLogfile(strLog);
}

IOReader::IOReader(QObject *parent, QString strRtuName)
	: QObject(parent)
{
    m_strRtuName = strRtuName;
    m_pRtuClient = new CXnSerial;// Client
   	m_bRtuOpened = false;
	
	//m_devAddr = KgGlobalData::ms_zz404D_addr;
    m_iDevIndex = 0;
	
	//m_devDoCount = KgGlobalData::ms_devDoCount;
	//m_devDiCount = KgGlobalData::ms_devDiCount;

	//KgGlobalData::ms_dryData.failedCount = 0;
	//KgGlobalData::ms_dryData.readDiCount = 0;
	//KgGlobalData::ms_dryData.IOCtrl = 0;
	//KgGlobalData::ms_dryData.DIVal = 0;
	
	//KgGlobalData::ms_dryData.bReadDiFlag = false;
	//KgGlobalData::ms_dryData.bReadDoFlag = false;
}

IOReader::~IOReader()
{

}

bool IOReader::openSerialPort()
{
   // step1.打开与串口继电器通信的串口
	if (!m_bRtuOpened)//还没有打开串口
	{
		sendLog(RUN_LOG_MESSAGE_DEV,  QString("DryCtrlThread Try to open dev(%1)...").arg(m_strRtuName));
		
		QByteArray tmpPort = m_strRtuName.toLocal8Bit();
		const char *portName = tmpPort.data();
        int ret = m_pRtuClient->openDevice(portName, B9600);
				 
		if (ret < 0)
		{
            sendLog(RUN_LOG_FAILED_DEV, QString("Open dev:%1 error,ret:%2.").arg(m_strRtuName).arg(ret));
			//msleep(5000);
			//continue;
		}
		else
		{
			sendLog(RUN_LOG_MESSAGE_DEV, QString("Open dev:%1 OK.").arg(m_strRtuName));
			m_bRtuOpened = true;
		}
	}

	return m_bRtuOpened;
}
		
int g_readDILogCount = 0;
//读取DI1--DI6的状态并判断消防告警
int IOReader::readDevDIState(int devIndex, DryData &dryData)
{
	/*
	读取4路DI (4路都断开）
	发送:FE 02 00 00 00 04 6D C6 
	接收:FE 02 01 00 91 9C 
	*/

	/*
	读取6路DI (6路都断开） 2020-02-20
	发送:FE 02 00 00 00 06 EC 07     
	接收:FE 02 01 00 91 9C   
	*/

	/*
	读取6路DI (第1路打开） 2020-02-21
	发送:FE 02 00 00 00 06 EC 07     
	接收:FE 02 01 01 50 5C 
	*/
	
	quint16 usDIState = 0; 
	for(int k = 0; k < 16; ++k)
	{
		if(KgGlobalData::ms_pIOModule->usDI[k] > 0) // usDI[16]
		{
			usDIState = usDIState | (1 << k);
		}
	}
    dryData.DIVal = usDIState; // added 2023-11-9 读取10寸屏自带的DI状态
    sendLog(0, QString("==================Read DI state(Frame3):%1.").arg(dryData.DIVal));
    return 0;
	
	
    uchar index = 0;
	bool  bHasEmerStopStrategy = false;
	bool  bHasWaterStrategy = false;
	
	m_pDataBuf[index++] = dryData.zz404D_addr;     // 控制器地址
	m_pDataBuf[index++] = DI_READ_CMD;   // 功能码:查询离散量输入（光耦)状态指令 

	int startAddr = dryData.diStartRegAddr;
	addParam2Buffer(m_pDataBuf+index, startAddr);// 起始地址:要查询的第一个光耦寄存器地址
	index += 2;

	addParam2Buffer(m_pDataBuf+index, dryData.devDiCount);// 寄存器个数:要查询的光耦寄存器数量
	index += 2;

	quint16 crcValue = Modbus_CRC16((uchar*)m_pDataBuf, index);
	addParam2Buffer(m_pDataBuf+index, crcValue);
	index += 2;

	int  nByte = m_pRtuClient->writeBlock((unsigned char*)m_pDataBuf, index);
	if (-1 ==nByte)
	{
		return nByte;
	}
	int step = 50;                     // 查询DI离散量输入（光耦)状态
	printSendInfo(step, m_pDataBuf, index);

	int iRetVal = readDevReplay(step, 6);
	if (iRetVal >= 6)
	{
		// KgGlobalData::ms_dryData.failedCount = 0;
		int needByteCount = 1;
		// added 2023-3-13
		if(dryData.devDiCount > 8)
		{
			if((dryData.devDiCount % 8) == 0)
			{
				needByteCount = dryData.devDiCount / 8;
			}
			else
			{
				needByteCount = (dryData.devDiCount / 8) + 1;
			}
		}
		iRetVal = analyRtuDatagram(dryData.zz404D_addr, m_pDataBuf, iRetVal, 1);
		if (0 == iRetVal)//查询成功
		{   
		    // 改为解析报文成功，才认为通迅成功 (上海电气西藏项目，线接反也误认为通迅正常) // modified 2022-3-30
			dryData.failedCount = 0;
			writeKgLogfile("|||||||||||||||||||||||||||||||||||||||||||||||||||failedCount = 0");
		    //g_DIState = m_readData[0];
		    quint16 oldDIState = dryData.DIVal;
			if(dryData.devDiCount > 8)
			{
				dryData.DIVal = m_readData[0] + m_readData[1] * 256 ;
			}
			else
			{
				dryData.DIVal = m_readData[0];
			}
			
			// 第一次读取到DI值，或读到到的DI值发生了变化
		    if (0 == dryData.readDiCount || oldDIState != dryData.DIVal) 
		   	{
		   		if(dryData.readDiCount < 3)
				{
					dryData.readDiCount += 1;
					/*
					if(MAX_IODEV_COUNT > 1) // modified 2022-8-2
					{
						if(isChLang())
			   		   	   saveLogToBaDb(QString("读取到#%1串口继电器输入状态:%2.").arg(devIndex+1).arg(dryData.DIVal));
					    else
					       saveLogToBaDb(QString("Read DI state of #%1 IODev:%2.").arg(devIndex+1).arg(dryData.DIVal));
					}
					else
					{
						if(isChLang())
			   		   	   saveLogToBaDb(QString("读取到串口继电器输入状态:%1.").arg(dryData.DIVal));
					    else
					       saveLogToBaDb(QString("Read DI state of IODev:%2.").arg(dryData.DIVal));
					}
					*/		
				}
		   	}
			
			if (dryData.readDiCount < 100)
			{
				dryData.readDiCount += 1; 
			}
		}
		else
		{
			/* deleted 2020-6-9
			if (connFailedCount >= 3) // 通信故障
			{
				g_bReadDiFlag = 0;
			}
			*/
			iRetVal = -2;
			if (dryData.failedCount < 50000)
			{
				dryData.failedCount += 1;
			}
			sendLog(RUN_LOG_FAILED_DEV, QString("AnalyRtuDatagram ret:%1.").arg(iRetVal));
		}
	}
	else
	{
		iRetVal = -1;
		if (dryData.failedCount < 50000)
		{
			dryData.failedCount += 1;
		}

		/* deleted 2020-6-9
		if (connFailedCount >= 3)// 通信故障
		{
			g_bReadDiFlag = 0;
		}
		*/
	}

	return iRetVal;
}

//读取DO1--DO6的状态
// [2021:07:01:10:05:47][发送]FE 01 00 00 00 04 29 C6 
// [2021:07:01:10:05:47][接收]FE 01 01 02 E0 5D  
int IOReader::readDevDOState(int devIndex, DryData &dryData)
{
	/*
	读取4路DO  (第1路闭合,即继电器打开）
	发送:FE 01 00 00 00 04 29 C6 
	接收:FE 01 01 01 A0 5C 
	*/

    /*
	读取6路DO  (6路都断开） 2020-02-20
	发送:FE 02 00 00 00 06 EC 07 
	接收:FE 02 01 00 91 9C
	*/

	/*
	读取6路DO  (第3,6路打开） 2020-02-21
	发送:FE 01 00 00 00 06 A8 07
	接收:FE 01 01 24 61 87
	*/
	sendLog(0, "==================Read DO state(Frame1).");
	
	quint16 usDOState = 0;
	for(int k = 0; k < 12; ++k)
	{
		if(KgGlobalData::ms_pIOModule->usDOState[k] > 0) // usDOState[12];  // 干接点1状态
		{
			usDOState = usDOState | (1 << k);
		}
	}
    dryData.IOCtrl = usDOState; // added 2023-11-9  读取10寸屏自带的DO状态
    return 0;
	

	uchar index = 0;
	m_pDataBuf[index++] = dryData.zz404D_addr;     // 控制器地址
	m_pDataBuf[index++] = DO_READ_CMD;   // 功能码:查询继电器状态指令

	int startAddr = dryData.doStartRegAddr;
	addParam2Buffer(m_pDataBuf+index, startAddr);   // 起始地址:要查询的第一个继电器地址
	index += 2;

	addParam2Buffer(m_pDataBuf+index, dryData.devDoCount);// 寄存器个数:要查询的继电器状态数量
	index += 2;

	quint16 crcValue = Modbus_CRC16((uchar*)m_pDataBuf, index);//count_CRC
	addParam2Buffer(m_pDataBuf+index, crcValue);
	index += 2;

	int  nByte = m_pRtuClient->writeBlock((unsigned char*)m_pDataBuf, index);
	if (-1 ==nByte)
	{
		return nByte;
	}

	int step = 51;                       // 查询继电器状态
	printSendInfo(step, m_pDataBuf, index);

    int iRetVal = readDevReplay(step, 6);
	if (iRetVal >= 6)
	{
	    int needByteCount = 1;
		// added 2023-3-13
		if(dryData.devDoCount > 8)
		{
			if((dryData.devDoCount % 8) == 0)
			{
				needByteCount = dryData.devDoCount / 8;
			}
			else
			{
				needByteCount = (dryData.devDoCount / 8) + 1;
			}
		}
		iRetVal = analyRtuDatagram(dryData.zz404D_addr, m_pDataBuf, iRetVal, needByteCount);
		if (0 == iRetVal)//查询成功
		{
		    //g_DOState = m_readData[0];
			//g_bReadDoFlag = 1;//作标记已经读取
			if(dryData.devDoCount > 8)
			{
				dryData.IOCtrl = m_readData[0] * 256 + m_readData[1];
			}
			else
			{
				dryData.IOCtrl = m_readData[0]; // support most 8 DO
			}
			//KgGlobalData::ms_dryData.bReadDoFlag = true;
			//printf("get DO1-6 state:%d\n", g_DOState);
		}
		else
		{
		    sendLog(RUN_LOG_FAILED_DEV, QString("analyRtuDatagram ret:%1").arg(iRetVal));
		}
	}

	return iRetVal;
}

// 站号+ 命令码+ 首个线圈的通讯地址+ 写入的线圈个数+写入的字节数+ 写入数值+ CRC校验和
// 01 0F 00 00 00 10 02|01 00 E3 B0    // 写入16个数据，地址0的值为1,   地址1~15的值为0
// 01 0F 00 00 00 10 02|03 00 CRC      // 写入16个数据，地址0和1的值为1,地址2~15的值为0
// 01 0F 00 00 00 11 03|03 00 00 CRC   // 写入17个数据，地址0和1的值为1,地址2~16的值为0

//设置DO成功返回8个字节
//[发送][2021:06:30:19:16:03] FE 0F 00 00 00 02 01 03 D1 92  // 控制打开DO1，DO2
//[接收][2021:06:30:19:16:03] FE 0F 00 00 00 02 C0 05 

//[发送][2021:07:02:08:57:32] FE 0F 00 00 00 04 01 0C 71 97  // 控制打开DO3，DO4
//[接收][2021:07:02:08:57:32] FE 0F 00 00 00 04 40 07     

//设置DO失败只返回5个字节
//[发送][2021:07:02:09:03:01] FE 1F 00 00 00 04 01 BC 61 E2
//[接收][2021:07:02:09:03:01] FE 9F 01 B8 00
int IOReader::setDevAllDoState(int devIndex, DryData &dryData)
{
	sendLog(0, "==================SetDevAllDoState.");

	uchar index = 0;
	m_pDataBuf[index++] = dryData.zz404D_addr;     // 控制器地址
	m_pDataBuf[index++] = DO_SET_CMD;                       // 控制多个DO指令

	quint16 startAddr = dryData.doStartRegAddr;
	addParam2Buffer(m_pDataBuf+index, startAddr);            // 起始地址:要查询的第一个继电器地址
	index += 2;

	addParam2Buffer(m_pDataBuf+index, (quint16)dryData.devDoCount);// 寄存器个数:要查询的继电器状态数量
	index += 2;

	int byteCount = (dryData.devDoCount+7)/8;
	*(m_pDataBuf+index) = byteCount;                         // 写入的字节数
	index += 1;

	if(1 == byteCount)
	{
		*(m_pDataBuf+index) = dryData.IOCtrl;
		index += 1;
	}
	else
	{
		*(m_pDataBuf+index) = (char)dryData.IOCtrl;               // 先写前8个地址的数据
		index += 1; 

		*(m_pDataBuf+index) = (char)(dryData.IOCtrl >> 8);        // 再写后8个地址的数据
		index += 1;
	}

	quint16 crcValue = Modbus_CRC16((uchar*)m_pDataBuf, index);// count_CRC
	addParam2Buffer(m_pDataBuf+index, crcValue);
	index += 2;

	int  nByte = m_pRtuClient->writeBlock((unsigned char*)m_pDataBuf, index);
	if (-1 ==nByte)
	{
		return nByte;
	}
	int step = 51;                                            // 查询继电器状态
	printSendInfo(step, m_pDataBuf, index);

    int iRetVal = readDevReplay(step, 6);
	if (iRetVal >= 6)
	{
		iRetVal = analySetMultDatagram15(dryData.zz404D_addr, m_pDataBuf, iRetVal, startAddr, dryData.devDoCount);
		sendLog(RUN_LOG_FAILED_DEV, QString("analySetMultDatagram15 ret:%1").arg(iRetVal));
	}

	return iRetVal;
}

int IOReader::readDevReplay(quint16 step, quint16 desiredLen)
{
	int length;
	unsigned int i;
	unsigned int totalLength = 0;
	unsigned int succeedCount = 0;
	unsigned int failedCount = 0;
	QString strHint;

	int timeoutMsec = KgGlobalData::ms_dryData.rwTimeoutSec * 1000;
	if(timeoutMsec < 300)
	{
		timeoutMsec = 300;
	}
	if(timeoutMsec > 3000)
	{
		timeoutMsec = 3000;
	}

	writeKgLogfile(QString("timeoutMsec============%1").arg(timeoutMsec));

	for(i = 0; i < 50; ++i)	
	{
		length = m_pRtuClient->readBlock((unsigned char *)m_pDataBuf+totalLength, RECE_BUFFER_LENGHT, timeoutMsec);
		//add by zyx 2018-8-9 begin
		if (length <= 0)
		{
			failedCount++;
			strHint = QString("DryCtrlThread %1th, recv len:%2, total len:%3, disired len:%4")
				.arg(i+1).arg(length).arg(totalLength).arg(desiredLen);
			sendLog(RUN_LOG_FAILED_DEV, strHint);
			if (failedCount >= 1)// 读取1次失败，则返回
			{
				return totalLength;
			}
		}
		else
		{
			succeedCount++;
			printReceInfo(step, m_pDataBuf+totalLength, length);
			totalLength += length;
			//strHint = QString("AcThread %1th, recv len:%2, total len:%3, disired len:%4")
			//	.arg(i+1).arg(length).arg(totalLength).arg(desiredLen);
			//sendLog(RUN_LOG_MESSAGE_DEV, strHint);
			if (totalLength >= desiredLen)//数据接收已经完整
			{
				break;
			}
		}
		//add by zyx 2018-8-9 end
	}
	return totalLength;
}

int IOReader::analyRtuDatagram(quint16 uaDevAddr, char* pRecDataBuf, int iLen, int needByteCount)
{
	if(0 == pRecDataBuf || iLen < 6)
	{
		return -1;
	}
	/*
	读取DI (6路都断开）
	time:2020-02-20 10:07:53, send data:FE 02 00 00 00 06 EC 07     
	time:2020-02-20 10:07:53, recv data:FE 02 01 00 91 9C   
	*/
	
	// some varibales
	int iRetVal = 0;
	int iInedx = 0;
	uchar uaModbusAddr = 0;
	uchar uaFuncCode = 0;
	uchar uaByteNum = 0;

	uchar uaTemp8 = 0;
	quint16 usTemp16 = 0;
	quint32 uiTemp32 = 0;
	int pos;

	// 校验报文是否正确
	iInedx = 0;

	uaModbusAddr = (uchar)*(pRecDataBuf + iInedx);
	iInedx += 1;

	uaFuncCode = (uchar)*(pRecDataBuf + iInedx);
	iInedx += 1;

	// 字节数
	uaByteNum = (uchar)*(pRecDataBuf + iInedx);
	iInedx += 1;

	if (uaDevAddr != uaModbusAddr || iLen < uaByteNum + 5) // 校验失败
	{
		return -2;
	}

	//if (uaByteNum != regCount * 2)
	if (uaByteNum != needByteCount)
	{
	   return -3;
	}

	quint16 usCRC = Modbus_CRC16((uchar*)pRecDataBuf, (uchar)(uaByteNum+3));
	quint16 oldCRC = 0;
	getParamFromBuffer(pRecDataBuf + uaByteNum+3, oldCRC);
	if (usCRC != oldCRC)
	{
		return -4;
	}

	for (pos = 0; pos < uaByteNum; ++pos)
	{
		m_readData[pos] = *(pRecDataBuf + iInedx);
		iInedx += 1;   
	}

	return iRetVal;
}

/*
//控制第1个DO口是否闭合(是否需要分励脱扣)
bool IOReader::setDoStateHZ(int doIndex, quint16 usNeedHz)
{
	QString strLog;

	if (doIndex >= m_devDoCount)
	{
		sendLog(0, "Do not have HZ node.");
		return false;
	}
	
	//const int doIndex = 0; //第1路DO
	if (doIndex >= m_devDoCount)
	{
		strLog = QString("==================SetDoStateHZ,doIndex:%1 is not right********.").arg(doIndex);
		sendLog(0, strLog);
		return false;
	}
	
	if (usNeedHz)//需要驱动
	{
	    strLog = QString("==================UsNeedHz:%1, set DO%2 to open********.").arg(usNeedHz).arg(doIndex+1);
		sendLog(0, strLog);
	    sendCtrlDoCmd(doIndex,1);
		
		int delayTime = KgGlobalData::ms_dryData.tkDelayTime * 1000;
	    //this->msleep(delayTime);//延时300ms
	    usleep(delayTime *1000);
	}

	strLog = QString("==================UsNeedHz:%1, set DO%2 to close********.").arg(usNeedHz).arg(doIndex+1);
	sendLog(0, strLog);
    //继电器闭合的动作，打开继电器不能超过1秒，否则会烧坏断路器**********************
    if (!sendCtrlDoCmd(doIndex,0))
    {
		return false;
    }
	
	int step = doIndex+1;
	int iRetVal = readDevReplay(step, 8);
	if (usNeedHz)
	{
		readDevReplay(step, 8);
	}

	return true;
}

//控制第2个DO口是否闭合(是否需要分励脱)
bool IOReader::setDoStateFZ(int doIndex, quint16 usNeedFz)
{
    QString strLog;
	
	if (doIndex >= m_devDoCount)
	{
		sendLog(0, "Do not have FZ node.");
		return false;
	}
	
	//const int doIndex = 1; //第2路DO
	if (doIndex >= m_devDoCount)
	{
		strLog = QString("==================SetDoStateFZ,doIndex:%1 is not right********.").arg(doIndex);
		sendLog(0, strLog);
		return false;
	}
	
	if (usNeedFz)//需要驱动
	{
	    strLog = QString("==================UsNeedFz:%1, set DO%2 to open********.").arg(usNeedFz).arg(doIndex+1);
		sendLog(0, strLog);
	    sendCtrlDoCmd(doIndex, 1);
		
		int delayTime = KgGlobalData::ms_dryData.tkDelayTime * 1000;
	    //this->msleep(delayTime);//延时300ms
	    usleep(delayTime *1000);
	}
	
	strLog = QString("==================UsNeedFz:%1, set DO%2 to close********").arg(usNeedFz).arg(doIndex+1);
	sendLog(0, strLog);
	//继电器闭合的动作，打开继电器不能超过1秒，否则会烧坏断路器**********************
    if (!sendCtrlDoCmd(doIndex,0))
    {
		return false;
    }
	
	int step = doIndex+1;
	int iRetVal = readDevReplay(step, 8);
	if (usNeedFz)
	{
		readDevReplay(step, 8);
	}

	return true;
}

//控制BCMU的DO口
void IOReader::setBankDoState(quint16 fireAlarm)           
{
    int i;
    //step1:每一组BC的DO3(低电压保护),DO4(告警灯)常开干结点控制
	for(i = 0; i < KgGlobalData::ms_installBankNum; ++i)
	{
		quint16 usHasProt = fireAlarm; 
		quint16 usSglDwnProt = 0;
		CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(i);//一组BC
		if (0 != pBank)
		{
			if (0xAAAA  == pBank->usBankState)//// BCMU Input 2（熔断器1状态） 
			{
			     usHasProt = 1;
			}

            //海基要求单体电压低于2.3V才会去动作DO3
            if (pBank->fSglMinVol < 2.3)
			//if (pBank->fSglMinVol < KgGlobalData::ms_sglProtVol)
			{
				  usSglDwnProt = 1;
				  usHasProt = 1;
			}
		}
		
		if (1 == usSglDwnProt)//需要低压保护 DO3
		{
		   printf("Bank%d SET DO3 with 1.\n",i+1);
		   if (0 == pBank->usDry3State)//还没有启动,进行开启 直流空开脱扣继电器K1
		    {
		    	pBank->usDry3Ctrl = 1; 
			    pBank->iDry3CtrlNum = 3;
		    }
		}
		else//不需要低压保护
		{
		    printf("Bank%d SET DO3 with 0.\n",i+1);
		    if (1 == pBank->usDry3State)//已经启动, 进行关闭
		    {
		    	pBank->usDry3Ctrl = 0; 
			    pBank->iDry3CtrlNum = 3;
		    }
		}
		

		if (1 == usHasProt)//需要开启霞光报警  DO4
		{
		   printf("Bank%d SET DO4 with 1.\n",i+1);
		   if (0 == pBank->usDry4State)//还没有启动,进行开启
		    {
		    	pBank->usDry4Ctrl = 1; 
			    pBank->iDry4CtrlNum = 3;
		    }
		}
		else//不需要开启霞光报警
		{
		    printf("Bank%d SET DO4 with 0.\n",i+1);
		    if (1 == pBank->usDry4State)//已经启动, 进行关闭
		    {
		    	pBank->usDry4Ctrl = 0; 
			    pBank->iDry4CtrlNum = 3;
		    }
		}
	}
}

bool IOReader::sendCtrlDoCmd(char doIndex, quint16 usSetVal)
{
    uchar index = 0;
	quint16 cmd = 0;
	
	m_pDataBuf[index++] = KgGlobalData::ms_dryData.zz404D_addr;  // 控制器地址
	m_pDataBuf[index++] = DO_CTRL_CMD;                   // 功能码:单个控制指令
	
	quint16 startAddr = KgGlobalData::ms_dryData.doStartRegAddr + doIndex;
	addParam2Buffer(m_pDataBuf+index, startAddr); // 寄存器地址:要控制继电器寄存地址
	index += 2;

    if (usSetVal) //需要打开
    {
    	cmd = 0xFF00; // 继电器开的动作
    }
	else
	{
		cmd = 0;     // 继电器关的动作
	}
	addParam2Buffer(m_pDataBuf+index, cmd);     // 寄存器值:继电器开和关的动作
	index += 2;

	quint16 crcValue = Modbus_CRC16((uchar*)m_pDataBuf, index);//count_CRC
	addParam2Buffer(m_pDataBuf+index, crcValue);
	index += 2;

	int  nByte = m_pRtuClient->writeBlock((unsigned char*)m_pDataBuf, index);
	if (-1 ==nByte)
	{
		return -1;
	}      
	printSendInfo(doIndex+1, m_pDataBuf, index);
	
	return true;
}
*/

int IOReader::analySetSingleDatagram(quint16 uaDevAddr, char* pRecDataBuf, int iLen, quint16 usRegAddr, quint16 usRegVal)
{
	int iRetVal = 0;
	int iInedx = 0;
	uchar uaModbusAddr = 0;
	uchar uaFuncCode = 0;
	quint16 usTemp16 = 0;

	quint16 usRepRegAddr =0;
	quint16 usRepRegVal =0;

	/*
	操作DO  打开第1个继电器
	发送:FE 05 00 00 FF 00 98 35 
	接收:FE 05 00 00 FF 00 98 35 
   */

	// 校验报文是否正确
	iInedx = 0;

	uaModbusAddr = (uchar)*(pRecDataBuf + iInedx);
	iInedx += 1;

	uaFuncCode = (uchar)*(pRecDataBuf + iInedx);
	iInedx += 1;

	if (uaDevAddr != uaModbusAddr || iLen < 8) // 校验失败
	{
		return -2;
	}

	if(DO_CTRL_CMD != uaFuncCode) // 控制DO继电器的打开或关闭 05
	{
		iRetVal = -3;
	}
	else
	{
	    getParamFromBuffer(pRecDataBuf + iInedx, usTemp16);
		iInedx += 2;
		usRepRegAddr= usTemp16;          // addr

		getParamFromBuffer(pRecDataBuf + iInedx, usTemp16);
		iInedx += 2;
		usRepRegVal= usTemp16;          // value

		quint16 usCRC = Modbus_CRC16((uchar*)pRecDataBuf, (uchar)(iInedx));
		quint16 oldCRC = 0;
		getParamFromBuffer(pRecDataBuf + iInedx, oldCRC);
		if (usCRC != oldCRC)
		{
			return -4;
		}

		if(usRepRegAddr == usRegAddr && usRepRegVal==usRegVal)
		{
		    iRetVal = 0;
		}
		else
		{
			iRetVal = -5;
		}	
	}

	return iRetVal;
}

void IOReader::AddSetCmd(quint16  uaRegAddr, quint16 uaRegValue, quint16 sleepTime)
{
    SPcsSetCmd cmd;
	cmd.uaRegAddr = uaRegAddr;
	cmd.fUserValue = uaRegValue;
	cmd.uaRegValue = uaRegValue;
	cmd.sleepTime = sleepTime;
	
	m_mutex.lock();
	m_dryCmdList.append(cmd);
	m_mutex.unlock();
}

int IOReader::formSetMultgram15(uchar uaAddr, quint16 usRegAddr, quint16 regCount, quint16 usRegVal, char* pSendDataBuf)
{
	int iLenVal = 0;
	quint16 usTemp = 0;
	uchar byteCount = 0;

	*(pSendDataBuf + iLenVal) = uaAddr;
	iLenVal += 1;

	*(pSendDataBuf + iLenVal) = 0x0F;//uaFuncCode;
	iLenVal += 1;

	usTemp = usRegAddr;
	addParam2Buffer(pSendDataBuf + iLenVal, usTemp);
	iLenVal += 2;

	usTemp = regCount;
	addParam2Buffer(pSendDataBuf + iLenVal, usTemp);
	iLenVal += 2;
	
	if(regCount%8 > 0)
		byteCount = regCount/8+1;
	else
		byteCount = regCount/8;	

	*(pSendDataBuf + iLenVal) = byteCount;  
	iLenVal += 1;

	//for(int i = 0; i < ucTemp; ++i)
	//{
	//	*(pSendDataBuf + iLenVal) = usRegVal; // support most 8 DO
	//	iLenVal += 1;
	//}
	
	// modified 2023-8-12
	if(1 == byteCount)
	{
		*(pSendDataBuf + iLenVal) = (usRegVal & 0xFF); // support most 8 DO
		iLenVal += 1;
	}
	else
	{
		for(int i = 0; i < byteCount; ++i)
		{
			if(0 == i)
			{
				*(pSendDataBuf + iLenVal) = (usRegVal & 0xFF);  // 先发低8位 modified 2023-8-21
			}
			else
			{
				*(pSendDataBuf + iLenVal) = (usRegVal >> 8);    // 再发高8位 
			}
			iLenVal += 1;
	     }
     }

	quint16 crcValue = Modbus_CRC16((uchar*)pSendDataBuf, iLenVal);//count_CRC
	addParam2Buffer(pSendDataBuf+iLenVal, crcValue);
	iLenVal += 2;

	return iLenVal;
}

int IOReader::analySetMultDatagram15(uchar uaAddr,char* pRecDataBuf, int iLen, quint16 usRegAddr, quint16 regCount)
{
	// some varibales
	int iRetVal = 0;
	int iInedx = 0;
	quint16 usEvent = 0;
	quint16 usLen = 0;
	uchar uaModbusAddr = 0;
	uchar uaFuncCode = 0;
	uchar uaByteNum = 0;

	uchar uaTemp8 = 0;
	quint16 usTemp16 = 0;
	quint32 uiTemp32 = 0;
	float fTemp = 0;

	quint16 usRepRegAddr =0;
	quint16 modifiedCount =0;

	/* 
	控制关闭DO1，打开DO2，3，4
	[2021:07:01:10:10:42][发送]FE 0F 00 00 00 04 01 0E F0 56 
    [2021:07:01:10:10:42][接收]FE 0F 00 00 00 04 40 07 
	*/
	
	iInedx = 0;

	uaModbusAddr = (uchar)*(pRecDataBuf + iInedx);
	iInedx += 1;

	uaFuncCode = (uchar)*(pRecDataBuf + iInedx);
	iInedx += 1;

	if (uaAddr != uaModbusAddr)
	{
		return -2;
	}

	if(0x0F != uaFuncCode)
	{
		iRetVal = -3;
	}
	else
	{
		getParamFromBuffer(pRecDataBuf + iInedx, usRepRegAddr);  //addr
		iInedx += 2;      

		getParamFromBuffer(pRecDataBuf + iInedx, modifiedCount); //register count
		iInedx += 2;  

		quint16 oldCRC = 0;
	    getParamFromBuffer(pRecDataBuf + iInedx, oldCRC);
		iInedx += 2;

		quint16 usCRC = Modbus_CRC16((uchar*)pRecDataBuf, (uchar)(iInedx-2));
	    if (usCRC != oldCRC)
		{
			return -3;
		}

		if(usRepRegAddr==usRegAddr && regCount==modifiedCount)
		{
			iRetVal = 0;
		}
		else
		{
			iRetVal = -4;
		}	
	}
	
	return iRetVal;
}

void IOReader::DealwithSetDoCmd(int devIndex, DryData &dryData)
{
	int succeedCount = 0;
	int iIndexStep = 50;	
	int iRetVal = 0;
	int iErrNum = 0;
	int i;
	QList<SPcsSetCmd> dryCmdList;

	if(0 == m_dryCmdList.size())
	{
		return;
	}
		
    m_mutex.lock();
	dryCmdList = m_dryCmdList;
	m_dryCmdList.clear();
	m_mutex.unlock();

	memset(m_pDataBuf, 0, 500);
	
	for(i = 0; i < dryCmdList.size(); ++i) // 处理设置遥控遥调（设置保持寄存器)命令
	{
		SPcsSetCmd cmd = dryCmdList[i];
		QString strLog = QString("||||||||==================Set DO state(Frame2).uaRegValue:%1")
			.arg(cmd.uaRegValue);
		sendLog(0, strLog);
		
		CIOModule *pIOModule = KgGlobalData::ms_pIOModule;
		for(int k = 0; k < dryData.devDoCount; ++k)
		{
			int maskVal = (1 << k);
			if((maskVal & cmd.uaRegValue) > 0)
			{
			     pIOModule->usDOCtrl[k] = (pIOModule->usDOCtrl[k] | maskVal);
			}
			else
			{
				 pIOModule->usDOCtrl[k] = (pIOModule->usDOCtrl[k] & (~maskVal));
			}
		}
		
		if(cmd.sleepTime > 0) // added 2023-11-23
		{
		   writeKgLogfile(QString("Sleep %1 ms...").arg(cmd.sleepTime));
		   //this->msleep(cmd.sleepTime);
		   usleep(cmd.sleepTime * 1000);
		   printDiDoState();
		}
		continue;// added 2023-11-9  *************************
		

		iRetVal = formSetMultgram15(dryData.zz404D_addr, dryData.doStartRegAddr,
			dryData.devDoCount,cmd.uaRegValue, m_pDataBuf);
		if (iRetVal >= 0)
		{
		   printSendInfo(iIndexStep, m_pDataBuf, iRetVal);
		   int  nByte = m_pRtuClient->writeBlock((unsigned char*)m_pDataBuf, iRetVal);
			if (-1 ==nByte)
			{
				++iErrNum;
				sendLog(0, QString("Write data(%2) to DryDev FAILED."));
			}
			else
			{
				// receive data
				int iRetVal = readDevReplay(iIndexStep, 6);
				if (iRetVal < 5)
				{
					++iErrNum;
					sendLog(0, QString("Write data to DryDev timeout."));
				}
				else
				{
					iRetVal = analySetMultDatagram15(dryData.zz404D_addr,m_pDataBuf,iRetVal,
						dryData.doStartRegAddr,dryData.devDoCount);
					writeKgLogfile(QString("AnalySetMultDatagram15 ret:%1.").arg(iRetVal));
					
					if(0 == iRetVal)
					{
						writeKgLogfile(QString("Set Control Mode OK."));
						++succeedCount;
						dryData.IOCtrl = cmd.uaRegValue;						
					}
					else
					{
						writeKgLogfile(QString("Set Control Mode Failed."));
					}
					
					iErrNum = 0; 
				}
				
				if(cmd.sleepTime > 0)
				{
				   writeKgLogfile(QString("Sleep %1 ms...").arg(cmd.sleepTime));
				   //this->msleep(cmd.sleepTime);
				   usleep(cmd.sleepTime * 1000);
				}
			}
		}
	}
	
   // if (succeedCount == m_dryCmdList.size())
   //   m_dryCmdList.clear();
   
}

